package com.atguigu.spzx.manager.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.atguigu.spzx.exception.BaseException;
import com.atguigu.spzx.exception.LoginException;
import com.atguigu.spzx.manager.constants.RedisConstant;
import com.atguigu.spzx.manager.service.ISysRoleService;
import com.atguigu.spzx.manager.service.ISysUserRoleService;
import com.atguigu.spzx.model.vo.common.dto.system.LoginDto;
import com.atguigu.spzx.model.vo.common.dto.system.SysUserDto;
import com.atguigu.spzx.model.vo.common.entity.system.SysRole;
import com.atguigu.spzx.model.vo.common.entity.system.SysUser;
import com.atguigu.spzx.manager.mapper.SysUserMapper;
import com.atguigu.spzx.manager.service.ISysUserService;
import com.atguigu.spzx.model.vo.common.vo.system.CaptchaVo;
import com.atguigu.spzx.model.vo.common.vo.system.LoginVo;
import com.atguigu.util.JwtUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;


import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.atguigu.spzx.constants.ExceptionConstants.*;
import static com.atguigu.spzx.manager.constants.RedisConstant.CAPTCHA;
import static com.atguigu.spzx.manager.constants.RedisConstant.CAPTCHA_TTL;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 宋哥
 * @since 2023-12-25
 */
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

     @Autowired
     private StringRedisTemplate stringRedisTemplate;
     @Autowired
     private ISysRoleService sysRoleService;
     @Autowired
     private ISysUserRoleService sysUserRoleService;
     @Autowired
     private SysUserMapper sysUserMapper;
    /**
     * 登录服务
     * @param loginDto
     * @return
     */
    public LoginVo login(LoginDto loginDto) {
        //1.根据用户名查询用户
        String username = loginDto.getUsername();
        String codeKey = loginDto.getCodeKey();
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        List<SysUser> list = list
                (wrapper.eq(StringUtils.isNotBlank(username), SysUser::getUsername, username));
        //2.判用户是否存在
        if(CollectionUtils.isEmpty(list)){
            //不存在返回错误
            log.info(USERNAME_IS_NOT_EXISTS);
            throw new LoginException(USERNAME_IS_NOT_EXISTS);
        }
        //3.判断用户密码是否正确
        SysUser user = list.get(0);
        if(!DigestUtils.md5DigestAsHex(loginDto.getPassword().getBytes()).equals(user.getPassword())){
            //密码不正确
            log.info(PASSWORD_ERROR);
            throw new LoginException(PASSWORD_ERROR);
        }
        //4.判断验证码是否存在
        //在redis中查询验证码
        String captchaCode = stringRedisTemplate.opsForValue().get(CAPTCHA + codeKey);
        //判断验证码是否正确
        if(StringUtils.isEmpty(captchaCode)||!loginDto.getCaptcha().equalsIgnoreCase(captchaCode)){
            //验证码不存在或者验证码不匹配
            log.info(CAPTCHA_ERROR);
            //清楚验证码在redis中
            stringRedisTemplate.delete(CAPTCHA + codeKey);
            throw new LoginException(CAPTCHA_ERROR);
        }
        //5.生成token,返回
        Long id = user.getId();
        String token = JwtUtil.genAccessToken(id);
        String userStr = JSONUtil.toJsonStr(user);
        //5.存入redis,设置时长为30min
        stringRedisTemplate.opsForValue().set(RedisConstant.ADMIN_LOGIN+ id.toString(),userStr,RedisConstant.LOGIN_TTL, TimeUnit.MINUTES);
        //清楚验证码数据
        stringRedisTemplate.delete(CAPTCHA+codeKey);
        return new LoginVo(token,null);
    }

    /**
     * 生成验证码
     * @return
     */
    public CaptchaVo generateValidateCode() {
        //1.生成随机codeKey
        String code = UUID.randomUUID().toString().replace("-","");
        //2.生验证码
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(150, 48, 4, 20);
        //验证码的值
        String captchaValue = captcha.getCode();
        //图片验证码
        String imageBase64 = captcha.getImageBase64();//base64编码
        //3.存入redis,设置过期时间
        stringRedisTemplate.opsForValue().set(CAPTCHA+code,captchaValue,CAPTCHA_TTL,TimeUnit.MINUTES);
        //4.封装数据并返回
        CaptchaVo captchaVo = new CaptchaVo();
        captchaVo.setCodeKey(code);
        captchaVo.setCodeValue("data:image/png;base64," + imageBase64);
        return captchaVo;
    }

    /**
     * 用户退出
     */
    public void logout(String token) {
        //获取用户信息
        Object id = null;
        try {
            id = JwtUtil.parsePayload(token).get("id");
        } catch (Exception e) {
            log.info("token解析失败,获取用户信息失败");
        }
        //移除redis信息
        stringRedisTemplate.delete(RedisConstant.ADMIN_LOGIN+ id);
    }

    /**
     * 条件分页查询用户信息
     * @param pageNum
     * @param pageSize
     * @param sysUserDto
     * @return
     */
    public Page<SysUser> selectUserByPage(Integer pageNum, Integer pageSize, SysUserDto sysUserDto) {
          Page<SysUser> page = new Page<>(pageNum, pageSize);
          List<SysUser> sysUserList= sysUserMapper.page(page,sysUserDto);
        sysUserList.forEach(sysUser -> sysUser.setPassword(""));
          return page.setRecords(sysUserList);
    }

    /**
     * 新增用户
     * @param sysUser
     */
    public void saveSysUser(SysUser sysUser) {
        //1.根据username查询一下用户,判断用户名是否重复
        String username = sysUser.getUsername();
        //如果存在会返回异常信息
        if(userNameIsExists(username)){
            throw new BaseException("用户名已存在");
        }
        //2.默认状态为启用状态
        sysUser.setStatus(1);
        sysUser.setIsDeleted(0);
        //3.将密码进行加密
        sysUser.setPassword(DigestUtils.md5DigestAsHex(sysUser.getPassword().getBytes()));
        //保存
        try {
            save(sysUser);
        } catch (Exception e) {
            throw new BaseException("保存失败");
        }
    }
    /*
    * 判断当前用户是否存在
    * */
    private boolean userNameIsExists(String username) throws BaseException {
        LambdaQueryWrapper<SysUser> wrapper =
                new LambdaQueryWrapper<SysUser>()
                        .eq(StrUtil.isNotBlank(username), SysUser::getUsername, username);
        List<SysUser> sysUserList = sysUserMapper.selectList(wrapper);
        if(CollectionUtil.isNotEmpty(sysUserList)){
            //已存在
            return true;
        }
        return false;
    }

    /**
     * 修改用户
     * @param sysUser
     */
    @Transactional
    public void updateSysUser(SysUser sysUser) {
        //此处仅仅修改用户信息,不作密码的修改
        if (StrUtil.isBlank(sysUser.getPassword())) {
            //1.判断用户名是否重复,出现异常会抛出异常信息
            String username = sysUser.getUsername();
            Long id = sysUser.getId();
            //构造查询条件,查询除了当前id以外的用户是否有与当前修改的用户名相同
            LambdaQueryWrapper<SysUser> wrapper =
                             new LambdaQueryWrapper<SysUser>()
                            .eq(StrUtil.isNotBlank(username), SysUser::getUsername, username)
                            .ne(id!=null,SysUser::getId,id);
            List<SysUser> sysUserList = sysUserMapper.selectList(wrapper);
            if(CollectionUtil.isNotEmpty(sysUserList)){
                //存在与输入的用户名相同的用户名
                throw new BaseException("用户名已存在");
            }
            //不存在
            int i = sysUserMapper.updateSysUser(sysUser);
            if(i<=0){
                    throw new BaseException("修改失败");
                }
        }else{
            throw new BaseException("此处不能修改密码");
        }
    }

    /**
     * 根据id删除用户
     * @param id
     */
    @Transactional
    public void deleteById(Long id) {
        int i = sysUserMapper.deleteById(id);
        if(i<=0){
            //说明删除失败
            throw new BaseException("删除失败");
        }
    }


    @Override
    public Map<String,Object> showRolesOfUser(Long userId) {
        //1.查询所用角色
        List<SysRole> allRoles = sysRoleService.findAllRoles();
        //2.查询当前userId所拥有的角色
        List<Long> sysRoleByUserId = sysUserRoleService.findSysRoleByUserId(userId);
        HashMap<String, Object> map = new HashMap<>();
        map.put("allRoles",allRoles);
        map.put("withRoles",sysRoleByUserId);
        //3.封装结果，返回
        return map;
    }


}
